サイトマップ / C言語講座>出入り口>総目次>目次:ファイル>二分木探索(バイナリサーチ)||デモ用
[空白文字の出現頻度]←このソース→[バッファリング有り無し]
/* まず最初にこのファイルを開いて下さい。そして、ファイル名を”Wtest.c”に変更しておいてください。今日は、Cのソースプログラムから、英単語を抜き出して、Cの予約語かどうか調べて、予約語だったらカウントするプログラムを作ります。
予約語とカウンタはセットになっている方が自然なので、構造体の配列を使います。構造体の配列は下に示すように型宣言をします。name[10] に予約語を入れ、countに数えた結果を入れます。
typedef struct {
char name[10];
int count;
} KEYWORD;
構造体の配列を下記のように宣言します。予約語は、後に述べる 二分木探索に使うので、整列してあります。
KEYWORD keyword[NUM_KW] = {
{"break", 0}
{"case", 0},
- - - - - - -
- - - - - - -
{"while", 0}
};
では、プログラムの流れについて、考えて見ましょう。
ファイルから英単語を読み込む関数の名前を、GetWord( ) とします。この関数は引数として、ファイルポインタと、取り出した英単語をしまう文字列へのポインタを取ります。戻り値は成功したら読み込んだ文字数を、失敗したら0を返すようにします。
単語を取り出すには、ライブラリ関数、strtok( ) を使っても良いと思います。しかし、strtok( ) は1回目と2回目以降の呼び出しで、引数を変えなければならず、使いづらいので、今回は自作することにします。
英単語はアルファベットでできています。そこで、次のアルゴリズムで英単語を読み込みます。
ファイルの先頭から1文字ずつ読み、
もし、アルファベットでなければ、読み飛ばし、
アルファベットなら、英単語をしまう配列に、その文字を書き込みます。
それをアルファベットでない文字が出るまで続け、
アルファベットでない文字が来たら、
文字列の終末にヌル文字を追加して、読み込んだ文字数をリターンする。
アルファベットかどうかは、下記のライブラリ関数を使って調べます。
#include <ctype.h>
int isalpha(char c);
例:n = isalpha(c);
実行結果 戻り値
条件を満たせば 0以外の値
条件を満たさなければ 0
ソースプログラムに詳しい説明を付けておきましたが、少し、補足します。int 型の変数 n に読み込んだ文字数を入れます。c = getc(fp) で、ファイルから c に1文字読み込みます。
if (!n && !isalpha(c)) が真になるのは、まだ1文字も読んでいなくて、かつ、c がアルファベットでない時です。この時は、読み飛ばします。if (n && !isalpha(c)) が真になるのは、文字を読み込んでいて、かつ、c がアルファベットでない時です。つまり、英単語を読み終わった時です。補足は、以上です。
次に、ファイルから読み込んだ単語が予約語かどうか調べて、予約語ならカウントする関数を作ります。この関数は、読み込んだ英単語をしまってある文字列へのポインタを取ります。戻り値は、予約語だった時は、見つけた位置 ( 後述 ) を返します。下記に関数の名前を示します。
int BSearch(char *word);
予約語であるかどうかは、構造体の配列の中に、英単語と同じものがあるかどうかを、調べればわかります。
予約語の探索には、バイナリサーチ ( 二分木探索 ) という方法を使います。バイナリサーチを行うには、データが昇順に整列してあることが必要です。英単語の場合は、辞書のような順に並んでいるということです。
このアルゴリズムについて説明します。左から右に辞書順に予約語が並んでいるとします。
英単語と、予約語の並びの中央のものと比較します。
もし、一致したら予約語の位置を返して、終了します。
もし、予約語の方が大きければ、次の探索対象は中央値の右側です。
もし、予約語の方が小さければ、次の探索対象は中央値の左側です。
このように、順次探索の範囲をせばめていって、分割不能になったら、-1 を返して終了します。
ソースプログラムに詳しい説明をつけて置きましたので、あとはそちらをごらん下さい。探索結果を表示する関数は、簡単なのでソースプログラムをごらん下さい。 */
#include <stdio.h>
#include <stdlib.h> /* exit( ) で必要 */
#include <string.h> /* strcmp( ) で必要 */
#include <ctype.h> /* isalpha( ) で必要 */
#define NUM_KW 25 /* 25 の予約語を対象にする */
typedef struct {
char name[10]; /* Cの予約語を入れる */
int count; /* カウンタ */
} KEYWORD;
/* 構造体配列の宣言 */
KEYWORD keyword[NUM_KW] = { /* 二分木探索 ( バイナリサーチ ) に使うので */
{"break", 0}, /* 構造体の最初の要素は整列してある */
{"case", 0},
{"char", 0},
{"continue", 0},
{"do", 0},
{"double", 0},
{"else", 0},
{"enum", 0},
{"extern", 0},
{"float", 0},
{"for", 0},
{"if", 0},
{"int", 0},
{"long", 0},
{"register", 0},
{"return", 0},
{"short", 0},
{"static", 0},
{"struct", 0},
{"switch", 0},
{"typedef", 0},
{"union", 0},
{"unsigned", 0},
{"void", 0},
{"while", 0}
};
int GetWord(FILE *fp, char *temp);
int BSearch(char *word);
void ShowResult(void);
void main(void);
/* 英単語を temp[n] に読み込む */
int GetWord(FILE *fp, char *temp)
{
int c;
int n = 0; /* 読み込んだ文字数 */
while ((c = getc(fp)) != EOF) {
/* 文字を 読み込んでいなくて */
if (!n && !isalpha(c)) /* かつ、c はアルファベットでない */
continue; /* 読み飛ばす */
else if (n && !isalpha(c)) { /* 英単語を読みおわったら */
temp[n] = '\0'; /* 末尾にヌル文字を付けて */
return (n); /* 読み込んだ文字数を返す */
}
else if (isalpha(c)) { /* アルファベットの時 */
temp[n] = (char)c; /* 英単語の読み込み */
n++;
}
}
return (0); /* キーワードの読み込みに失敗 */
}
/* 二分木探索 ( バイナリサーチ ) を行って、 */
/* 予約語が見つかったら、カウンタに1加える */
int BSearch(char *word)
{
int left = 0;
int right = NUM_KW - 1;
int mid;
int x;
/* 左から右へ辞書的に予約語が並んでいるとすると */
while (left <= right) {
mid = left + (right - left) / 2;
x = strcmp(keyword[mid].name, word);
if (x > 0) /* 予約語は mid より左にある */
right = mid -1; /* 左を探索 */
else if (x < 0) /* 予約語は mid より右にある */
left = mid + 1; /* 右を探索 */
else { /* 見つかったら */
keyword[mid].count += 1; /* カウンタに1加えて、 */
return (mid); /* リターンする */
}
}
return (-1);
}
/* 構造体の中身を表示 */
void ShowResult(void)
{
int i;
for (i = 0; i < NUM_KW ; i++) {
printf("%10s %3d ", keyword[i].name, keyword[i].count);
if (!((i + 1) % 4)) /* 予約語を4つ表示したら改行 */
printf("\n");
}
}
void main(void)
{
FILE *fp;
char word[100];
if ((fp = fopen("wtest.c", "r")) == NULL) { /* ファイルを開けなかったら */
fprintf(stderr, "Can't Open C Source File!\n");/* メッセージを表示して */
exit(2); /* シェルへ戻る */
}
/* 英単語が見つかったら予約語かどうか調べる */
while (GetWord(fp, word)) {
BSearch(word) ;
}
ShowResult( ) ;
fclose(fp);
}
|
/* このプログラムで開いたファイル "Wtest.c" は、このプログラムから日本語のコメントを削ったファイルです。 */
[空白文字の出現頻度]←このソース→[バッファリング有り無し]
/* (C) 2000- YFプロ. All Rights Reserved. */ 提供:C言語講座−それ自体コンパイルできる教材を使った講座です−